/**********************************************************************************************************************
 * @file    gnss_command.c
 * @author  Queclink Jason.Huang
 * @date    2018-12-27
 * @brief   Queclink FreeRTOS Software Development Kit gnss task source.
 *
 * Copyright (C) 2018 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @attention
 *
 *********************************************************************************************************************/

/* includes ---------------------------------------------------------------------------------------------------------*/
#include <qlcommon.h>
#include <gnss_public.h>
#include <gnss_info_process.h>
#include <stdarg.h>
#include <gnss_command.h>
/* Macro ------------------------------------------------------------------------------------------------------------*/
#define GNSS_PARAM_LEN		(4)

/* Type----------------------------------------------------------------------------------------------------------------- */


/* Global Variable --------------------------------------------------------------------------------------------------*/
struct list_head gnss_cmd_list = LIST_HEAD_INIT(gnss_cmd_list);	/* gnss_cmd_list_t */

extern void *mtkSeries01_CmdSearch(int cmd_id);
/* Function --------------------------------------------------------------------------------------------------------- */
/* 命令注册
 * param:
 *   cmd_id: 命令 ID, 见 gnss_cmd_id
 *   callback: 命令执行结果回调函数
 * return:
 * 	 0: 注册成功
 *   -EEXIST: 指令已存在,正在执行
 *   others: 错误码
 */
int gnss_cmd_register(int cmd_id, void (*callback)(int cmd_id, int res))
{
	struct list_head *pos,*pn;
	gnss_cmd_list_t *cmd;
	const struct gnss_cmd_table_t  *impl = NULL;

	list_for_each_safe(pos, pn, &gnss_cmd_list){
		cmd = list_entry(pos, gnss_cmd_list_t, list);
		if (cmd->id == cmd_id)
			return -EEXIST;
	}

	impl = (const struct gnss_cmd_table_t  *)(mtkSeries01_CmdSearch(cmd_id));

	if (NULL == impl)
		return -EPERM;

	/* 注册命令 */
	cmd = qlmalloc(sizeof(gnss_cmd_list_t));
	if (cmd == NULL)
		return -ENOMEM;

	memset(cmd, 0, sizeof(gnss_cmd_list_t));
	cmd->id = cmd_id;
	cmd->impl = impl;
	cmd->callback = callback;

	list_add_tail(&(cmd->list), &gnss_cmd_list);
	return 0;
}


static void gnss_cmd_del(gnss_cmd_list_t *node)
{
	if (NULL != node) {
		list_del(&(node->list));
		if (NULL != node->cps.ptr)
			qlfree(node->cps.ptr);
		qlfree(node);
	}
}


/* 命令清空 */
void gnss_cmd_del_all(void)
{
	struct list_head *pos,*pn;
	gnss_cmd_list_t *cmd;

	list_for_each_safe(pos, pn, &gnss_cmd_list){
		cmd = list_entry(pos, gnss_cmd_list_t, list);
		gnss_cmd_del(cmd);
	}
}


/* 获取当前正在执行的指令
 * NULL, 没有执行中的指令
 */
gnss_cmd_list_t *gnss_cmd_get_first(void)
{
	struct list_head *list_ptr,*n= NULL;
	gnss_cmd_list_t *cmd = NULL;
	if (!list_empty(&gnss_cmd_list)) {
		list_for_each_safe(list_ptr,n, &gnss_cmd_list){
			cmd = list_entry(list_ptr, gnss_cmd_list_t, list);
			return cmd;
		}
	}
	return NULL;
}


/* GNSS 命令处理进程, 任务主循环调用
 */
void gnss_cmd_process(void* task_param)
{
	struct list_head *pos,*pn;
	gnss_cmd_list_t *cmd;
	int ret;

	list_for_each_safe(pos, pn, &gnss_cmd_list){
		cmd = list_entry(pos, gnss_cmd_list_t, list);
		ret = cmd->impl->impl(&(cmd->cps));
		if (-EBUSY != ret) {
			if (NULL != cmd->callback)
				cmd->callback(cmd->id, ret);
			gnss_cmd_del(cmd);
		}
		return;
	}
}
